﻿using NLog;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UeyesAIS.DataDefinition;

namespace UeyesAIS.Service.ImageProcess
{
    /// <summary>
    /// 图像处理通道，此通道为单独通道
    /// </summary>
    internal class ImageProcessGroup
    {
        private int _picCount;
        private bool _intime;
        private DateTime _dtstart;
        private ILogger _algprocess;
        private EnumResult _correctRlt;
        private ImageProcess _imageProc;//图像处理类    
        private List<Bitmap> _dustPicList;
        private ManualResetEvent _finishEvent;
        private List<Task> _listInspTask;
        private ConcurrentQueue<int> _cmdQueue;//命令队列
        private ConcurrentQueue<ImagaeInfo> _mapQueue;//图像队列

        public int InspShotCount;
        public string Groupname;
        public bool ContinueShot;
        public bool OnlyShotPic;
        public bool ReadLocal;
        public Bitmap VisiualImage;
        public List<string> CmdListStr;
        public InspGroupRecord Insprecord;//存储检测过程中的信息
        public ResultDisplayRowResult ResultAll;
        public event EventHandler<int> OnBackPicCount;
        public event EventHandler<GroupResult> OnBackGroupResult;
        public event EventHandler<Bitmap> RefrushContinueCapturePic;
        public event EventHandler<Bitmap> OnBackOneShot;
        public event EventHandler<ResultDisplayRowResult> DisGroupItemResult;

        #region 属性
        /// <summary>
        /// 拍图数量
        /// </summary>
        public int PictureCount
        {
            get { return _picCount; }
            set
            {
                if (value != _picCount)
                {
                    if (value == 0)
                    {
                        CmdListStr.Clear();
                    }
                    _picCount = value;
                    CmdListStr.Add("=========" + InspEntity.InspState.ToString() + "  拍图数量：" + value);
                    OnBackPicCount?.Invoke(Groupname, _picCount);
                }
            }
        }
        #endregion 属性

        #region 构造
        public ImageProcessGroup(CameraInfomation ci)
        {
            _algprocess = LogManager.GetLogger("alg");
            _imageProc = new ImageProcess("");
            _finishEvent = new ManualResetEvent(false);
            _imageProc.cameraID = ci.CameraName;
            _cmdQueue = new ConcurrentQueue<int>();
            _mapQueue = new ConcurrentQueue<ImagaeInfo>();
            _listInspTask = new List<Task>();
            _dustPicList = new List<Bitmap>();
            CmdListStr = new List<string>();
            Groupname = ci.CameraName;
            ResultAll = new ResultDisplayRowResult();
            Insprecord = new InspGroupRecord() { ImageSourceName = ci.CameraName };
            Task.Factory.StartNew(AnalyCmd, TaskCreationOptions.LongRunning);
        }
        #endregion 构造

        #region 图像解析
        public void CmdInqueue(int cmd)
        {
            _cmdQueue.Enqueue(cmd);
        }
        /// <summary>
        /// 图像解析
        /// </summary>
        /// <param name="ImageSource">图像源</param>
        /// <param name="bitmap">图像</param>
        public void ImageAnalysis(object ImageSource, Bitmap bitmap)
        {
            try
            {
                string cname = ImageSource.ToString();
                if (!cname.Equals(Groupname))
                {
                    BpjbCommon.Net.Core.BpEventHandler.ErrHandler(string.Format("相机来源不匹配，源{0}，目标{1}", cname, Groupname), BpjbCommon.Net.Core.ErrType.Warning);
                    return;
                }
                int aisindex = InspEntity.InspState;
                if ((Device.SaveSourceImage && !ContinueShot) || OnlyShotPic)//保存拍摄图片
                {
                    Bitmap temp = (Bitmap)bitmap.Clone();
                    Task.Run(() => SaveSourceImage(cname, aisindex, temp));
                }
                if (!ReadLocal && !Device.DitUseVirtual.All(x => x.Value))
                {
                    bitmap.Dispose();
                    return;
                }
                if (aisindex == 99)//None
                {
                    if (!ContinueShot)
                    {
                        OnBackOneShot?.Invoke(Groupname, (Bitmap)bitmap.Clone());
                    }
                    else
                    {
                        RefrushContinueCapturePic?.Invoke(ImageSource, (Bitmap)bitmap.Clone());
                    }
                    bitmap.Dispose();
                    bitmap = null;
                    return;
                }
                _mapQueue.Enqueue(new ImagaeInfo(cname, (Bitmap)bitmap.Clone()));
                bitmap.Dispose();
            }
            catch (Exception ex)
            {
                _algprocess.Error("ImageProcess异常" + ex.ToString());
            }
            finally
            {
                GC.Collect();
            }
        }
        private void AnalyCmd()
        {
            while (true)
            {
                if (_cmdQueue.Count <= 0 || _mapQueue.Count <= 0) continue;
                var cmd = 0;
                if (!_cmdQueue.TryDequeue(out cmd)) continue;
                ImagaeInfo map;
                if (_mapQueue.Count <= 0 || !_mapQueue.TryDequeue(out map)) continue;
                var sw = new Stopwatch();
                sw.Start();
                Console.WriteLine("指令队列解析指令图片" + cmd);
                ProcessImageCenter(map.Image, cmd);
                sw.Stop();
                Console.WriteLine("指令队列完成时间:" + sw.ElapsedMilliseconds);
            }
        }
        private Bitmap SaveSourceImage(string cname, int aisindex, Bitmap temp)
        {
            DateTime dtNow = DateTime.Now;
            string p = Path.Combine(Device.ExtraPathDir, cname, Device.defaultProduct.ProductName, DateTime.Now.ToString("yyyMMdd"), _imageProc.start.ToString("HHmmss"));
            if (!Directory.Exists(p))
            {
                Directory.CreateDirectory(p);
            }
            string name = "";
            if (aisindex >= -3 && aisindex <= 100)
            {
                var tp = Device.defaultProduct.ParamList.Find(x => x.PicParameter.Picindex == aisindex);
                name = tp == null ? "" : tp.PicParameter.Picname;
            }
            else if (aisindex == -4)
                name = "Mark";
            else
                name = "None";
            p += "\\" + string.Format("{0}-{1}{2}{3}-{4}_{5}_{6}-曝光{7}.png",
                name, dtNow.Year, dtNow.Month, dtNow.Day, dtNow.Hour, dtNow.Minute, dtNow.Second, Device.DeviceEntityControl.Cameras != null ? Device.DeviceEntityControl.Cameras[0].GetExprosetime() : 100);
            temp.Save(p);
            temp.Dispose();
            temp = null;
            return temp;
        }
        #endregion 图像解析

        #region 单组图处理
        /// <summary>
        /// 图像处理中心
        /// </summary>
        /// <param name="bitmap">图像</param>
        /// <param name="aisindex">命令字</param>
        private void ProcessImageCenter(Bitmap bitmap, int aisindex)
        {
            try
            {
                if (aisindex >= 0 && aisindex < 50)
                {
                    if (aisindex == Device.CorrectIndex)//等于1为校正
                    {
                        _algprocess.Info("当前相机丢包为" + DeviceService.Intance.DeviceEntityControl.Cameras[0].GetErrorCount());
                        var correctbitmap = (Bitmap)bitmap.Clone();
                        _listInspTask.Add(Task.Factory.StartNew(ProcessCorrect, correctbitmap));
                    }
                    else if (aisindex > 0)
                    {
                        _algprocess.Debug("Camera=>" + "进入检测线程索引, 当前图片索引：" + InspEntity.InspState.ToString());
                        var param = new InspImageInfo(new Bitmap[] { (Bitmap)bitmap.Clone() }, aisindex, false);
                        _listInspTask.Add(Task.Factory.StartNew(ProcessInspMap, param));
                    }
                    InspShotCount++;
                    PictureCount++;
                }
                else if (aisindex == -1 || aisindex == -3 || aisindex == -2)//除尘图和目测图
                {
                    PictureCount++;
                    if (aisindex == -1)//因目测调用ThreadInspColorPic方法，故图片数量和记录得同步
                    {
                        InspShotCount++;
                        if (VisiualImage != null)
                            VisiualImage.Dispose();
                        VisiualImage = (Bitmap)bitmap.Clone();
                    }
                    else
                        _dustPicList.Add((Bitmap)bitmap.Clone());
                }

            }
            catch (Exception ex)
            {
                _algprocess.Error("Camera=>" + Groupname + "ImageProcess:_{0}图片处理过程异常：{1}！", InspEntity.InspState.ToString(), ex.Message + ex.TargetSite);
            }
        }
        private void Aftercorrect(Bitmap reusebm)
        {
            if (VisiualImage != null && !_dustPicList.Contains(null) && _dustPicList.Count >= 2)
            {
                var bm1 = (Bitmap)_dustPicList[0].Clone();
                var bm2 = (Bitmap)_dustPicList[1].Clone();
                var param = new InspImageInfo(new Bitmap[] { VisiualImage, bm1, bm2 }, -1, false);
                _listInspTask.Add(Task.Factory.StartNew(ProcessInspMap, param));
            }
            var corrinfo = DeviceService.Intance.DefaultProduct.ParamList.Find(x => x.PicParameter.Picindex == Device.CorrectIndex);
            if (corrinfo.InspGroup[0].InspMethods.Count <= 1) return;
            var parama = new InspImageInfo(new Bitmap[] { reusebm }, Device.CorrectIndex, false);
            _listInspTask.Add(Task.Factory.StartNew(ProcessInspMap, parama));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="param"></param>
        internal void ProcessInspMap(object pm)
        {
            var unid = Device.UniqueID;
            var param = pm as InspImageInfo;
            try
            {
                var rowResult = _imageProc.ThreadInspColorPic(param);
                if (unid.Equals(Device.UniqueID) && unid != "")
                {
                    ProcessResult(rowResult);
                }
                else
                {
                    _algprocess.Warn(string.Format("检测项已舍弃:unid-{0},uniqueID-{1}", unid, Device.UniqueID));
                }
            }
            catch (Exception ex)
            {
                _algprocess.Error("ProcessInspMap:" + ex.ToString());
            }
        }
        /// <summary>
        /// 校正清灰
        /// </summary>
        /// <param name="cbitmap"></param>
        private void ProcessCorrect(object corrbitmap)
        {
            var cbitmap = corrbitmap as Bitmap;
            try
            {
                var copymap = (Bitmap)cbitmap.Clone();
                InspCorrect(cbitmap);
                for (int i = 0; i < _dustPicList.Count; i++)
                {
                    var t = new Task(InspDust, i);
                    t.Start();
                    t.Wait();
                    _listInspTask.Add(t);
                }
                Aftercorrect(copymap);
            }
            catch (Exception ex)
            {
                _algprocess.Error("ProcessCorrect:" + ex.ToString());
            }
        }

        internal bool InspCorrect(Bitmap correctbitmap)
        {
            var result = _imageProc.InspCorrectPic(correctbitmap);
            _correctRlt = result.Result ? EnumResult.Pass : EnumResult.Failed;
            OnRefrushListView(result);//通知主界面更新控件内容
            Insprecord.ListResults.Add(result);
            return _correctRlt.Equals(EnumResult.Pass);
        }

        private void OnRefrushListView(ResultDisplayRowResult result)
        {
            DisGroupItemResult?.Invoke(Groupname, result);
        }

        internal void InspDust(object ind)
        {
            var index = int.Parse(ind.ToString());
            if (index < _dustPicList.Count)
            {
                var map = (Bitmap)_dustPicList[index].Clone();
                ProcessDust(map, index);
            }
        }

        /// <summary>
        /// 清灰处理
        /// </summary>
        /// <param name="bitmap">图片</param>
        /// <param name="index">索引</param>
        private void ProcessDust(Bitmap bitmap, int index)
        {
            try
            {
                var dust = _imageProc.InspDustPic(bitmap, index);
                ProcessResult(dust);
            }
            catch (Exception ex)
            {
                _algprocess.Error(string.Format("ProcessDust异常{0}:{1}", index, ex.ToString()));
            }
        }
        private void ProcessResult(ResultDisplayRowResult rowResult)
        {
            try
            {
                #region 更新主机轮显界面
                #endregion

                #region 保存检查后图片
                if (DeviceService.Intance.Parameter.SaveInspImage) //
                {
                    Task.Factory.StartNew(() => SaveInspPic(rowResult));
                }
                #endregion

                OnRefrushListView(rowResult); //通知主界面更新控件内容
                Insprecord.ListResults.Add(rowResult);
            }
            catch (Exception ex)
            {
                var msg = "Null";
                if (rowResult != null)
                    msg = rowResult.ItemName;
                _algprocess.Error(string.Format("ProcessResult异常({0})：{1}", msg, ex.ToString()));
            }
        }

        #region 保存检测图片
        private void SaveInspPic(ResultDisplayRowResult ar)
        {
            var id = Groupname;
            if (ar == null)
                return;
            try
            {
                Bitmap bbm = (Bitmap)ar.InspedImg.Clone();
                if (bbm != null)
                {
                    var timeNow = System.DateTime.Now.ToLocalTime();
                    string name = string.Format("{0}-{1}", DateTime.Now.ToString("yyyyMMddHHmmssffff") + (string.IsNullOrEmpty(id) ? "" : id), string.Format("{0}-{1}", ar.ItemName, ar.Msg));
                    string path = string.Format("images\\{0}\\{1}\\{2}\\{3}", Groupname, DateTime.Now.ToString("yyyyMMdd"), DeviceService.Intance.DefaultProduct.ProductName, Device.UniqueID);
                    if (!System.IO.Directory.Exists(path))
                        System.IO.Directory.CreateDirectory(path);
                    bbm.Save(path + "\\" + name + ".png");
                    var tempCol = ar.ErrCol;
                    var tempRow = ar.ErrRow;
                    var tempValue = ar.ErrValue;
                    var tempType = ar.ErrType;
                    if (tempCol != null && tempCol.Count > 0)
                    {
                        System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(bbm.Width, bbm.Height);
                        System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap);
                        g.DrawImage(bbm, 0, 0, bbm.Width, bbm.Height);
                        var p = new Pen(Color.Red, 4);
                        for (int i = 0; i < tempCol.Count; i++)
                        {
                            int colc = (int)tempCol[i];
                            int rowc = (int)tempRow[i];
                            g.DrawRectangle(p, new Rectangle((int)colc - 20, (int)rowc - 20, 40, 40));
                            g.DrawString(string.Format("{0},{1}", tempType[i], tempValue[i]), new Font("宋体", 15, FontStyle.Regular),
                               new SolidBrush(Color.Blue), tempCol[i], tempRow[i]);
                        }
                        g.Dispose();
                        bitmap.Save(path + "\\" + name + "Err.png");
                        bitmap.Dispose();
                    }
                    bbm.Dispose();
                }
            }
            catch (Exception ex)
            {
                _algprocess.Error("Camera=>" + "CameraInsp-SavePic:"
                    + Groupname + "Save img ErrInfo:" + ex.Message);
            }
        }
        #endregion 保存检测图片

        #endregion 单组图处理

        #region 刷新
        internal void Refrush(int step)
        {
            #region 记录ID、作业员、线体名、站台号
            Insprecord.OperatorID = DeviceService.Intance.Parameter.CurentOperator;
            Insprecord.BatchID = DeviceService.Intance.Parameter.DefaultProductId;
            Insprecord.LineNO = DeviceService.Intance.Parameter.StationNO;
            ReadLocal = false;
            #endregion 记录ID、作业员、线体名、站台号

            #region 将每个相机的检测结果清零
            if (Insprecord.ListResults != null)
            {
                for (int i = 0; i < Insprecord.ListResults.Count; i++)
                {
                    var t = Insprecord.ListResults[i] as ResultDisplayRowResult;
                    if (t.ErrCol != null)
                        t.ErrCol.Clear();
                    if (t.ErrRow != null)
                        t.ErrRow.Clear();
                    if (t.ErrType != null)
                        t.ErrType.Clear();
                    if (t.ErrValue != null)
                        t.ErrValue.Clear();
                    if (t.InspedImg != null)
                    {
                        t.InspedImg.Dispose();
                        t.InspedImg = null;
                    }
                    GC.Collect();
                }
                Insprecord.ListResults.Clear();
            }
            else
            {
                Insprecord.ListResults = new List<BaseItemResult>();
            }
            #endregion 将每个相机的检测结果清零

            #region 相机采图数量、清灰图列表、指令队列清空
            InspShotCount = 0;
            PictureCount = 0;
            foreach (var dr in _dustPicList)
            {
                if (dr != null)
                    dr.Dispose();
            }
            _dustPicList.Clear();
            var cmd = 0;
            while (_cmdQueue.TryDequeue(out cmd))
            {

            }
            ImagaeInfo map;
            while (_mapQueue.TryDequeue(out map))
            {
                map.Image.Dispose();
            }
            _listInspTask.Clear();
            #endregion 相机采图数量、清灰图列表清空

            _imageProc.Refresh();
            _imageProc.InitAlgthom();
            _finishEvent.Reset();
            if (step != 0)
                return;
            Task.Factory.StartNew(InspTask, TaskCreationOptions.LongRunning);
        }

        private void InspTask()
        {
            try
            {
                _dtstart = DateTime.Now;
                Insprecord.StartTime = _dtstart.ToString("yyyyMMddHHmmssffff");
                ThreadPart _loadControl = new ThreadPart();
                var alg_finished = new Judger(() => (_listInspTask.Count == Device.InspRecordCount)
                && (Task.WaitAll(_listInspTask.ToArray(), Device.defaultProduct.Delaytime.AllResults)))
                { Name = "算法检测结束" };
                var result = alg_finished.Sure(_loadControl.CancelToken, _loadControl.ContinueEvent, _loadControl.StopEvent,
                    Device.defaultProduct.Delaytime.AllResults);
                #region 旧版本
                ////需要的电测图加目测图的数量  ---电测结果（含目测）+校正结果---
                //var piccount = Device.defaultProduct.ParamList.Count(x => (x.PicParameter.Picindex > -4 && x.PicParameter.Picindex < -1)
                //    || (x.PicParameter.Picindex > -2 && x.InspGroup[0].InspMethods.Count > 0));
                //var timeout = Device.defaultProduct.Delaytime.AllResults;
                //_algprocess.Info("等待电目测检测结果");
                //var corrinfo = Device.defaultProduct.ParamList.Find(x => x.PicParameter.Picindex == Device.CorrectIndex);
                //var condition1 = corrinfo.InspGroup[0].InspMethods.Count < 1;//仅矫正
                //while (timeout-- > 0)//等待检测结果
                //{
                //    if (!Device.Automode) //调试模式
                //    {
                //        var condition2 = condition1 ? piccount > Insprecord.ListResults.Count : piccount + 1 > Insprecord.ListResults.Count;
                //        if (piccount > PictureCount || condition2)
                //        {
                //            //实际拍图数量小于需要数量
                //            //或者结果数量不足
                //        }
                //        else//采图数量满足、结果数量满足
                //        {
                //            break;
                //        }
                //    }
                //    else if (Insprecord.ListResults.Any(x => !x.Result))
                //    {
                //        _algprocess.Info("自动模式，检测项结果有NG，结果NG");
                //        break;
                //    }
                //    Thread.Sleep(100);
                //}
                #endregion 旧版本
                _algprocess.Info(string.Format("等待电目测检测结果完成，图片计划数量{0},拍图数量{1},检测结果数量{2},{3}超时"
                    , Device.InspRecordCount, InspShotCount, _listInspTask.Count, result ? "未" : "已"));
                SaveRecords(result);
                _finishEvent.Set();
            }
            catch (Exception ex)
            {
                _finishEvent.Set();
                _algprocess.Error("InspTask异常：" + ex.ToString());
                ResultAll.Result = true;
            }
        }
        #region 汇总检测结果，保存记录
        private void SaveRecords(bool timeout)
        {
            var list = Insprecord.ListResults;
            var errType = -2;
            var gresult = new GroupResult();
            var f1 = list.All(x => x.Result == true);
            var f2 = list.Count == Device.InspRecordCount;
            var f3 = timeout;
            var f4 = _correctRlt.GetHashCode() == (EnumResult.pass).GetHashCode();
            if (f1 && f2 && f4)
            {
                Insprecord.InspResult = 1;
                _algprocess.Trace("检测结束：OK");
                gresult.Result = true;
                gresult.Msg = "检测结束：OK";
            }
            else
            {
                string text = string.Format("检测结束：NG，原因为：{0}|{1}|{2}|{3}", new object[]
                    {
                        f4 ? "" : "校正",
                        f1 ? "" : "检测",
                        f2 ? "" : "项数",
                        f3 ? "" : "超时"}).TrimEnd('|');
                _algprocess.Trace(text);
                gresult.Result = false;
                gresult.Msg = text;
                var temp = Insprecord.ListResults;
                if (f4 && temp.Any())
                {
                    if (temp.Any(x => ((ResultDisplayRowResult)x).ErrType.Any()))
                    {
                        var tfirst = temp.First(x => ((ResultDisplayRowResult)x).ErrType.Count > 0);
                        var queryResult = tfirst as ResultDisplayRowResult;
                        if (queryResult != null)
                            errType = queryResult.ErrType.First();
                    }
                }
                else
                    errType = -1;
                Insprecord.ErrCode = NGSort.TypeSort(errType);
                Insprecord.InspResult = 0;
            }
            #region 回传检测结果
            var dtend = DateTime.Now;
            Insprecord.Duaration = Convert.ToInt32(( dtend- _dtstart).TotalSeconds);
            Insprecord.EndTime = dtend.ToString("yyyyMMddHHmmssffff");
            gresult.ElapsedTime = Insprecord.Duaration;
            OnBackGroupResult?.Invoke(Groupname, gresult);
            #endregion

            #region 保存检测记录
            Task.Factory.StartNew(() =>
            {
                (new ExcelHandle()).SaveRecord(Insprecord, Groupname);
                if (Device.Parameter.SaveNgImage)
                    Insprecord.ListResults.ForEach(x =>
                   {
                       if (!x.Result) SaveInspPic(x as ResultDisplayRowResult);
                   });
            }, TaskCreationOptions.LongRunning);
            #endregion 保存检测记录
        }
        #endregion 汇总检测结果

        internal bool WaitFinished(int time = -1)
        {
            //等待检测结果
            _intime = _finishEvent.WaitOne(time);
            return _intime;
        }
        internal void RefreshDetial()
        {
            foreach (var item in Insprecord.ListResults)
                OnRefrushListView(item as ResultDisplayRowResult);
        }
        #endregion 
    }
}
